home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 November / november_2001.iso / Browsers / Netscape 6.1 / browser.xpi / bin / chrome / comm.jar / content / editor / EdDialogCommon.js < prev    next >
Encoding:
JavaScript  |  2001-06-12  |  31.2 KB  |  1,140 lines

  1. /*
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation. Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Pete Collins
  22.  *   Brian King
  23.  */
  24. /*
  25.   if we ever need to use a different string bundle, use srGetStrBundle
  26.   by including
  27.   <script language="javascript" src="chrome://global/content/strres.js"/>
  28.   e.g.:
  29.   var bundle = srGetStrBundle("chrome://global/locale/filepicker.properties");
  30. */
  31.  
  32. // Each editor window must include this file
  33. // Variables  shared by all dialogs:
  34. var editorShell;
  35. // Bummer! Can't get at enums from nsIDocumentEncoder.h
  36. var gOutputSelectionOnly = 1;
  37. var gOutputFormatted     = 2;
  38. var gOutputNoDoctype     = 4;
  39. var gOutputBodyOnly      = 8;
  40. var gOutputPreformatted  = 16;
  41. var gOutputWrap          = 32;
  42. var gOutputFormatFlowed  = 64;
  43. var gOutputAbsoluteLinks = 128;
  44. var gOutputEncodeEntities = 256;
  45. var gStringBundle;
  46. var gValidationError = false;
  47.  
  48. // Use for 'defaultIndex' param in InitPixelOrPercentMenulist
  49. var gPixel = 0;
  50. var gPercent = 1;
  51.  
  52. var maxPixels  = 10000;
  53. // For dialogs that expand in size. Default is smaller size see "onMoreFewer()" below
  54. var SeeMore = false;
  55.  
  56. // A XUL element with id="location" for managing
  57. // dialog location relative to parent window
  58. var gLocation;
  59.  
  60. // The element being edited - so AdvancedEdit can have access to it
  61. var globalElement;
  62.  
  63. function InitEditorShell()
  64. {
  65.     // get the editor shell from the parent window
  66.  
  67.   editorShell = window.opener.editorShell;
  68.   if (editorShell) {
  69.     editorShell = editorShell.QueryInterface(Components.interfaces.nsIEditorShell);
  70.   }
  71.   if (!editorShell) {
  72.     dump("EditorShell not found!!!\n");
  73.     window.close();
  74.     return false;
  75.   }
  76.  
  77.   // Save as a property of the window so it can be used by child dialogs
  78.  
  79.   window.editorShell = editorShell;
  80.  
  81.   return true;
  82. }
  83.  
  84. function StringExists(string)
  85. {
  86.   if (string != null && string != "undefined" && string.length > 0)
  87.     return true;
  88.  
  89.   return false;
  90. }
  91.  
  92. /* Validate contents of an input field 
  93.  *
  94.  *  inputWidget    The 'textbox' XUL element for text input of the attribute's value
  95.  *  listWidget     The 'menulist' XUL element for choosing "pixel" or "percent"
  96.  *                  May be null when no pixel/percent is used.
  97.  *  minVal         minimum allowed for input widget's value
  98.  *  maxVal         maximum allowed for input widget's value
  99.  *                 (when "listWidget" is used, maxVal is used for "pixel" maximum,
  100.  *                  100% is assumed if "percent" is the user's choice)
  101.  *  element        The DOM element that we set the attribute on. May be null.
  102.  *  attName        Name of the attribute to set.  May be null or ignored if "element" is null
  103.  *  mustHaveValue  If true, error dialog is displayed if "value" is empty string
  104.  *
  105.  *  This calls "ValidateNumberRange()", which puts up an error dialog to inform the user. 
  106.  *    If error, we also: 
  107.  *      Shift focus and select contents of the inputWidget,
  108.  *      Switch to appropriate panel of tabbed dialog if user implements "SwitchToValidate()",
  109.  *      and/or will expand the dialog to full size if "More / Fewer" feature is implemented
  110.  *
  111.  *  Returns the "value" as a string, or "" if error or input contents are empty
  112.  *  The global "gValidationError" variable is set true if error was found
  113.  */
  114. function ValidateNumber(inputWidget, listWidget, minVal, maxVal, element, attName, mustHaveValue, mustShowMoreSection)
  115. {
  116.   if (!inputWidget)
  117.   {
  118.     gValidationError = true;
  119.     return "";
  120.   }
  121.  
  122.   // Global error return value
  123.   gValidationError = false;
  124.   var maxLimit = maxVal;
  125.   var isPercent = false;
  126.  
  127.   var numString = inputWidget.value.trimString();
  128.   if (numString)
  129.   {
  130.     if (listWidget)
  131.       isPercent = (listWidget.selectedIndex == 1);
  132.     if (isPercent)
  133.       maxLimit = 100;
  134.  
  135.     // This method puts up the error message
  136.     numString = ValidateNumberRange(numString, minVal, maxLimit, mustHaveValue);
  137.     if(!numString)
  138.     {
  139.       // Switch to appropriate panel for error reporting
  140.       SwitchToValidatePanel();
  141.  
  142.       // or expand dialog for users of "More / Fewer" button
  143.       if ("dialog" in window && dialog && 
  144.            "MoreSection" in dialog && dialog.MoreSection)
  145.       {
  146.         if ( !SeeMore )
  147.           onMoreFewer();
  148.       }
  149.  
  150.       // Error - shift to offending input widget
  151.       SetTextboxFocus(inputWidget);
  152.       gValidationError = true;
  153.     }
  154.     else
  155.     {
  156.       if (isPercent)
  157.         numString += "%";
  158.       if (element)
  159.         element.setAttribute(attName, numString);
  160.     }
  161.   } else if (element) {
  162.     element.removeAttribute(attName);
  163.   }
  164.   return numString;
  165. }
  166.  
  167. /* Validate contents of an input field 
  168.  *
  169.  *  value          number to validate
  170.  *  minVal         minimum allowed for input widget's value
  171.  *  maxVal         maximum allowed for input widget's value
  172.  *                 (when "listWidget" is used, maxVal is used for "pixel" maximum,
  173.  *                  100% is assumed if "percent" is the user's choice)
  174.  *  mustHaveValue  If true, error dialog is displayed if "value" is empty string
  175.  *
  176.  *  If inputWidget's value is outside of range, or is empty when "mustHaveValue" = true,
  177.  *      an error dialog is popuped up to inform the user. The focus is shifted
  178.  *      to the inputWidget.
  179.  *
  180.  *  Returns the "value" as a string, or "" if error or input contents are empty
  181.  *  The global "gValidationError" variable is set true if error was found
  182.  */
  183. function ValidateNumberRange(value, minValue, maxValue, mustHaveValue)
  184. {
  185.   // Initialize global error flag
  186.   gValidationError = false;
  187.   value = TrimString(String(value));
  188.  
  189.   // We don't show error for empty string unless caller wants to
  190.   if (!value && !mustHaveValue)
  191.     return "";
  192.  
  193.   var numberStr = "";
  194.  
  195.   if (value.length > 0)
  196.   {
  197.     // Extract just numeric characters
  198.     var number = Number(value.replace(/\D+/g, ""));
  199.     if (number >= minValue && number <= maxValue )
  200.     {
  201.       // Return string version of the number
  202.       return String(number);
  203.     }
  204.     numberStr = String(number);
  205.   }
  206.  
  207.   var message = "";
  208.  
  209.   if (numberStr.length > 0)
  210.   {
  211.     // We have a number from user outside of allowed range
  212.     message = editorShell.GetString( "ValidateRangeMsg");
  213.     message = message.replace(/%n%/, numberStr);
  214.     message += "\n ";
  215.   }
  216.   message += editorShell.GetString( "ValidateNumberMsg");
  217.  
  218.   // Replace variable placeholders in message with number values
  219.   message = message.replace(/%min%/, minValue).replace(/%max%/, maxValue);
  220.   ShowInputErrorMessage(message);
  221.  
  222.   // Return an empty string to indicate error
  223.   gValidationError = true;
  224.   return "";
  225. }
  226.  
  227. function SetTextboxFocusById(id)
  228. {
  229.   SetTextboxFocus(document.getElementById(id));
  230. }
  231.  
  232. function SetTextboxFocus(textbox)
  233. {
  234.   if (textbox)
  235.   {
  236.     // Select entire contents
  237.     if (textbox.value.length > 0)
  238.       textbox.select();
  239.     else
  240.       textbox.focus();
  241.   }
  242. }
  243.  
  244. function ShowInputErrorMessage(message)
  245. {
  246.   editorShell.AlertWithTitle(GetString("InputError"), message);
  247.   window.focus();
  248. }
  249.  
  250. function GetString(name)
  251. {
  252.   if (editorShell)
  253.   {
  254.     return editorShell.GetString(name);
  255.   }
  256.   else
  257.   {
  258.     // Non-editors (like prefs) may use these methods
  259.     if (!gStringBundle)
  260.     {
  261.       gStringBundle = srGetStrBundle("chrome://editor/locale/editor.properties");
  262.       if (!gStringBundle)
  263.         return null;
  264.     }
  265.     return gStringBundle.GetStringFromName(name);
  266.   }
  267.   return null;
  268. }
  269.  
  270. function TrimStringLeft(string)
  271. {
  272.   if(!string) return "";
  273.   return string.replace(/^\s+/, "");
  274. }
  275.  
  276. function TrimStringRight(string)
  277. {
  278.   if (!string) return "";
  279.   return string.replace(/\s+$/, '');
  280. }
  281.  
  282. // Remove whitespace from both ends of a string
  283. function TrimString(string)
  284. {
  285.   if (!string) return "";
  286.   return string.replace(/(^\s+)|(\s+$)/g, '')
  287. }
  288.  
  289. String.prototype.trimString = function() {
  290.   return this.replace(/(^\s+)|(\s+$)/g, '')
  291. }
  292.  
  293. function IsWhitespace(string)
  294. {
  295.   return /^\s/.test(string);
  296. }
  297.  
  298. function TruncateStringAtWordEnd(string, maxLength, addEllipses)
  299. {
  300.     // Return empty if string is null, undefined, or the empty string
  301.     if (!string)
  302.       return "";
  303.  
  304.     // We assume they probably don't want whitespace at the beginning
  305.     string = string.replace(/^\s+/, '');
  306.     if (string.length <= maxLength)
  307.       return string;
  308.  
  309.     // We need to truncate the string to maxLength or fewer chars
  310.     if (addEllipses)
  311.       maxLength -= 3;
  312.     string = string.replace(RegExp("(.{0," + maxLength + "})\\s.*"), "$1")
  313.  
  314.     if (string.length > maxLength)
  315.       string = string.slice(0, maxLength);
  316.  
  317.     if (addEllipses)
  318.       string += "...";
  319.     return string;
  320. }
  321.  
  322. // Replace all whitespace characters with supplied character
  323. // E.g.: Use charReplace = " ", to "unwrap" the string by removing line-end chars
  324. //       Use charReplace = "_" when you don't want spaces (like in a URL)
  325. function ReplaceWhitespace(string, charReplace) {
  326.   return string.replace(/(^\s+)|(\s+$)/g,'').replace(/\s+/g,charReplace)
  327. }
  328.  
  329. // Replace whitespace with "_" and allow only HTML CDATA
  330. //   characters: "a"-"z","A"-"Z","0"-"9", "_", ":", "-", ".",
  331. //   and characters above ASCII 127
  332. function ConvertToCDATAString(string)
  333. {
  334.   return string.replace(/\s+/g,"_").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
  335. }
  336.  
  337. // this function takes an elementID and a flag
  338. // if the element can be found by ID, then it is either enabled (by removing "disabled" attr)
  339. // or disabled (setAttribute) as specified in the "doEnable" parameter
  340. function SetElementEnabledById( elementID, doEnable )
  341. {
  342.   var element = document.getElementById(elementID);
  343.   if ( element )
  344.   {
  345.     if ( doEnable )
  346.     {
  347.       element.removeAttribute( "disabled" );
  348.     }
  349.     else
  350.     {
  351.       element.setAttribute( "disabled", "true" );
  352.     }
  353.   }
  354.   else
  355.   {
  356.     dump("Element "+elementID+" not found in SetElementEnabledById\n");
  357.   }
  358. }
  359.  
  360. // This function relies on css classes for enabling and disabling
  361. // This function takes an ID for a label and a flag
  362. // if an element can be found by its ID, then it is either enabled or disabled
  363. // The class is set to either "enabled" or "disabled" depending on the flag passed in.
  364. // This function relies on css having a special appearance for these two classes.
  365.  
  366. function SetClassEnabledById( elementID, doEnable )
  367. {
  368.   element = document.getElementById(elementID);
  369.   if ( element )
  370.   {
  371.     if ( doEnable )
  372.     {
  373.      element.setAttribute( "class", "enabled" );
  374.     }
  375.     else
  376.     {
  377.      element.setAttribute( "class", "disabled" );
  378.     }
  379.   }
  380.   else
  381.   {
  382.     dump( "not changing element "+elementID+"\n" );
  383.   }
  384. }
  385.  
  386. // Get the text appropriate to parent container
  387. //  to determine what a "%" value is refering to.
  388. // elementForAtt is element we are actually setting attributes on
  389. //  (a temporary copy of element in the doc to allow canceling),
  390. //  but elementInDoc is needed to find parent context in document
  391. function GetAppropriatePercentString(elementForAtt, elementInDoc)
  392. {
  393.   var name = elementForAtt.nodeName.toLowerCase();
  394.   if ( name == "td" || name == "th")
  395.     return GetString("PercentOfTable");
  396.  
  397.   // Check if element is within a table cell
  398.   // Check if current selection anchor node is within a table cell
  399.   if (editorShell.GetElementOrParentByTagName("td", elementInDoc))
  400.     return GetString("PercentOfCell");
  401.   else
  402.     return GetString("PercentOfWindow");
  403. }
  404.  
  405. function InitPixelOrPercentMenulist(elementForAtt, elementInDoc, attribute, menulistID, defaultIndex)
  406. {
  407.   if (!defaultIndex) defaultIndex = gPixel;
  408.  
  409.   var size  = elementForAtt.getAttribute(attribute);
  410.   var menulist = document.getElementById(menulistID);
  411.   var pixelItem;
  412.   var percentItem;
  413.  
  414.   if (!menulist)
  415.   {
  416.     dump("NO MENULIST found for ID="+menulistID+"\n");
  417.     return size;
  418.   }
  419.  
  420.   ClearMenulist(menulist);
  421.   pixelItem = AppendStringToMenulist(menulist, GetString("Pixels"));
  422.  
  423.   if (!pixelItem) return 0;
  424.  
  425.   percentItem = AppendStringToMenulist(menulist, GetAppropriatePercentString(elementForAtt, elementInDoc));
  426.   if (size && size.length > 0)
  427.   {
  428.     // Search for a "%" character
  429.     var percentIndex = size.search(/%/);
  430.     if (percentIndex > 0)
  431.     {
  432.       // Strip out the %
  433.       size = size.substr(0, percentIndex);
  434.       if (percentItem)
  435.         menulist.selectedItem = percentItem;
  436.     }
  437.     else
  438.       menulist.selectedItem = pixelItem;
  439.   }
  440.   else
  441.     menulist.selectedIndex = defaultIndex;
  442.  
  443.   return size;
  444. }
  445.  
  446. function AppendStringToMenulistById(menulist, stringID)
  447. {
  448.   return AppendStringToMenulist(menulist, editorShell.GetString(stringID));
  449. }
  450.  
  451. function AppendStringToMenulist(menulist, string)
  452. {
  453.   if (menulist)
  454.   {
  455.     var menupopup = menulist.firstChild;
  456.     // May not have any popup yet -- so create one
  457.     if (!menupopup)
  458.     {
  459.       menupopup = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menupopup");
  460.       if (menupopup)
  461.         menulist.appendChild(menupopup);
  462.       else
  463.       {
  464.         dump("Failed to create menupoup\n");
  465.         return null;
  466.       }
  467.     }
  468.     var menuItem = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
  469.     if (menuItem)
  470.     {
  471.       menuItem.setAttribute("label", string);
  472.       menupopup.appendChild(menuItem);
  473.       return menuItem;
  474.     }
  475.   }
  476.   return null;
  477. }
  478.  
  479. function AppendLabelAndValueToMenulist(menulist, labelStr, valueStr)
  480. {
  481.   if (menulist)
  482.   {
  483.     var menupopup = menulist.firstChild;
  484.     // May not have any popup yet -- so create one
  485.     if (!menupopup)
  486.     {
  487.       menupopup = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menupopup");
  488.       if (menupopup)
  489.         menulist.appendChild(menupopup);
  490.       else
  491.       {
  492.         dump("Failed to create menupoup\n");
  493.         return null;
  494.       }
  495.     }
  496.     var menuItem = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
  497.     if (menuItem)
  498.     {
  499.       menuItem.setAttribute("label", labelStr);
  500.       menuItem.setAttribute("value", valueStr);
  501.       menupopup.appendChild(menuItem);
  502.       return menuItem;
  503.     }
  504.   }
  505.   return null;
  506. }
  507.  
  508. function ClearMenulist(menulist)
  509. {
  510.   // Always use "AppendStringToMenulist" so we know there's 
  511.   //  just one <menupopup> as 1st child of <menulist>
  512.   if (menulist) {
  513.     menulist.selectedItem = null;
  514.     var popup = menulist.firstChild;
  515.     if (popup)
  516.       while (popup.firstChild)
  517.         popup.removeChild(popup.firstChild);
  518.   }
  519. }
  520.  
  521. /* These help using a <tree> for simple lists
  522.   Assumes this simple structure:
  523.   <tree>
  524.     <treecolgroup><treecol flex="1"/></treecolgroup>
  525.     <treechildren>
  526.       <treeitem>
  527.         <treerow>
  528.           <treecell label="the text the user sees"/>
  529. */
  530.  
  531. function AppendStringToTreelistById(tree, stringID)
  532. {
  533.   return AppendStringToTreelist(tree, editorShell.GetString(stringID));
  534. }
  535.  
  536. function AppendStringToTreelist(tree, string)
  537. {
  538.   if (tree)
  539.   {
  540.     var treecols = tree.firstChild;
  541.     if (!treecols)
  542.     {
  543.       dump("Bad XUL: Must have <treecolgroup> as first child\n");
  544.     }
  545.     var treechildren = treecols.nextSibling;
  546.     if (!treechildren)
  547.     {
  548.       treechildren = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "treechildren");
  549.       if (treechildren)
  550.       {
  551.         treechildren.setAttribute("flex","1");
  552.         tree.appendChild(treechildren);
  553.       }
  554.       else
  555.       {
  556.         dump("Failed to create <treechildren>\n");
  557.         return null;
  558.       }
  559.     }
  560.     var treeitem = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "treeitem");
  561.     var treerow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "treerow");
  562.     var treecell = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "treecell");
  563.     if (treeitem && treerow && treecell)
  564.     {
  565.       treerow.appendChild(treecell);
  566.       treeitem.appendChild(treerow);
  567.       treechildren.appendChild(treeitem)
  568.       treecell.setAttribute("label", string);
  569.       //var len = Number(tree.getAttribute("length"));
  570.       //if (!len) len = -1;
  571.       tree.setAttribute("length", treechildren.childNodes.length);
  572.       return treeitem;
  573.     }
  574.   }
  575.   return null;
  576. }
  577.  
  578. function ReplaceStringInTreeList(tree, index, string)
  579. {
  580.   if (tree)
  581.   {
  582.     var treecols = tree.firstChild;
  583.     if (!treecols)
  584.     {
  585.       dump("Bad XUL: Must have <treecolgroup> as first child\n");
  586.       return;
  587.     }
  588.     var treechildren = treecols.nextSibling;
  589.     if (!treechildren)
  590.       return;
  591.  
  592.     // Each list item is a <treeitem><treerow><treecell> under <treechildren> node
  593.     var childNodes = treechildren.childNodes;
  594.     if (!childNodes || index >= childNodes.length)
  595.       return;
  596.  
  597.     var row = childNodes.item(index).firstChild;
  598.     if (row && row.firstChild)
  599.     {
  600.       row.firstChild.setAttribute("label", string);
  601.     }
  602.   }
  603. }
  604.  
  605. function ClearTreelist(tree)
  606. {
  607.   if (tree)
  608.   {
  609.     tree.clearItemSelection();
  610.     // Skip over the first <treecolgroup> child
  611.     if (tree.firstChild)
  612.     {
  613.       nextChild = tree.firstChild.nextSibling;
  614.       while (nextChild)
  615.       {
  616.         var nextTmp = nextChild.nextSibling;
  617.         tree.removeChild(nextChild);
  618.         nextChild = nextTmp;
  619.       }
  620.     }
  621.     // Count list items
  622.     tree.setAttribute("length", 0);
  623.   }
  624. }
  625.  
  626. function GetSelectedTreelistAttribute(tree, attr)
  627. {
  628.   if (tree)
  629.   {
  630.     if (tree.selectedIndex >= 0 &&
  631.         tree.selectedItems.length > 0 &&
  632.         tree.selectedItems[0] &&
  633.         tree.selectedItems[0].firstChild &&
  634.         tree.selectedItems[0].firstChild.firstChild)
  635.     {
  636.       return tree.selectedItems[0].firstChild.firstChild.getAttribute(attr);
  637.     }
  638.   }
  639.   return "";
  640. }
  641.  
  642. function GetSelectedTreelistValue(tree)
  643. {
  644.   return GetSelectedTreelistAttribute(tree,"label")
  645. }
  646.  
  647. function RemoveSelectedTreelistItem(tree)
  648. {
  649.   if (tree)
  650.   {
  651.     if (tree.selectedIndex >= 0 &&
  652.         tree.selectedItems.length > 0)
  653.     {
  654.       // Get the node to delete
  655.       var treeItem = tree.selectedItems[0];
  656.       if (treeItem)
  657.       {
  658.         tree.clearItemSelection();
  659.         var parent = treeItem.parentNode;
  660.         if (parent)
  661.         {
  662.           parent.removeChild(treeItem);
  663.           tree.setAttribute("length", parent.childNodes.length);
  664.         }
  665.       }
  666.     }
  667.   }
  668. }
  669.  
  670. function GetTreelistValueAt(tree, index)
  671. {
  672.   if (tree)
  673.   {
  674.     var item = tree.getItemAtIndex(index);
  675.     if (item && item.firstChild && item.firstChild.firstChild)
  676.       return item.firstChild.firstChild.getAttribute("label");
  677.   }
  678.   return "";
  679. }
  680.  
  681. function forceInteger(elementID)
  682. {
  683.   var editField = document.getElementById( elementID );
  684.   if ( !editField )
  685.     return;
  686.  
  687.   var stringIn = editField.value;
  688.   if (stringIn && stringIn.length > 0)
  689.   {
  690.     // Strip out all nonnumeric characters
  691.     stringIn = stringIn.replace(/\D+/g,"");
  692.     if (!stringIn) stringIn = "";
  693.  
  694.     // Write back only if changed
  695.     if (stringIn != editField.value)
  696.       editField.value = stringIn;
  697.   }
  698. }
  699.  
  700. function LimitStringLength(elementID, length)
  701. {
  702.   var editField = document.getElementById( elementID );
  703.   if ( !editField )
  704.     return;
  705.  
  706.   var stringIn = editField.value;
  707.   if (stringIn && stringIn.length > length)
  708.     editField.value = stringIn.slice(0,length);
  709. }
  710.  
  711.  
  712. function onAdvancedEdit()
  713. {
  714.   // First validate data from widgets in the "simpler" property dialog
  715.   if (ValidateData())
  716.   {
  717.     // Set true if OK is clicked in the Advanced Edit dialog
  718.     window.AdvancedEditOK = false;
  719.     // Open the AdvancedEdit dialog, passing in the element to be edited
  720.     //  (the copy named "globalElement")
  721.     window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", globalElement);
  722.     window.focus();
  723.     if (window.AdvancedEditOK)
  724.     {
  725.       // Copy edited attributes to the dialog widgets:
  726.       InitDialog();
  727.     }
  728.   }
  729. }
  730.  
  731. function GetSelectionAsText()
  732. {
  733.   return editorShell.GetContentsAs("text/plain", gOutputSelectionOnly);
  734. }
  735.  
  736.  
  737. // ** getSelection ()
  738. // ** This function checks for existence of table around the focus node
  739. // ** Brian King - XML Workshop
  740.  
  741. function getContainer ()
  742. {
  743.   tagName = "img";
  744.   selImage = editorShell.GetSelectedElement(tagName);
  745.   if (selImage)  // existing image
  746.   {
  747.     oneup = selImage.parentNode;
  748.     return oneup;
  749.   }
  750.   else if (!selImage)  // new image insertion
  751.   {
  752.     dump("Not an image element -- Trying for caret selection\n");
  753.     var selection = window.editorShell.editorSelection;
  754.     if (selection)
  755.     {
  756.         var focusN = selection.focusNode;
  757.         if (focusN.nodeName.toLowerCase == "td")
  758.           return focusN
  759.                 else
  760.         {
  761.           oneup = focusN.parentNode;
  762.           return oneup;
  763.          }
  764.     }
  765.     else
  766.       return null;
  767.    }
  768.    else
  769.      return null;
  770. }
  771.  
  772. function getColor(ColorPickerID)
  773. {
  774.   var colorPicker = document.getElementById(ColorPickerID);
  775.   var color;
  776.   if (colorPicker)
  777.   {
  778.     // Extract color from colorPicker and assign to colorWell.
  779.     color = colorPicker.getAttribute("color");
  780.     if (color && color == "")
  781.       return null;
  782.     // Clear color so next if it's called again before
  783.     //  color picker is actually used, we dedect the "don't set color" state
  784.     colorPicker.setAttribute("color","");
  785.   }
  786.  
  787.   return color;
  788. }
  789.  
  790. function setColorWell(ColorWellID, color)
  791. {
  792.   var colorWell = document.getElementById(ColorWellID);
  793.   if (colorWell)
  794.   {
  795.     if (!color || color == "")
  796.     {
  797.       // Don't set color (use default)
  798.       // Trigger change to not show color swatch
  799.       colorWell.setAttribute("default","true");
  800.       // Style in CSS sets "background-color",
  801.       //   but color won't clear unless we do this:
  802.       colorWell.removeAttribute("style");
  803.     }
  804.     else
  805.     {
  806.       colorWell.removeAttribute("default");
  807.       // Use setAttribute so colorwell can be a XUL element, such as button
  808.       colorWell.setAttribute("style", "background-color:"+color);
  809.     }
  810.   }
  811. }
  812.  
  813. function getColorAndSetColorWell(ColorPickerID, ColorWellID)
  814. {
  815.   var color = getColor(ColorPickerID);
  816.   setColorWell(ColorWellID, color);
  817.   return color;
  818. }
  819.  
  820. // Test for valid image by sniffing out the extension
  821. function IsValidImage(imageName)
  822. {
  823.   var image = imageName.trimString();
  824.   if ( !image )
  825.     return false;
  826.  
  827.   /* look for an extension */
  828.   var tailindex = image.lastIndexOf(".");
  829.   if ( tailindex == 0 || tailindex == -1 ) /* -1 is not found */
  830.     return false;
  831.  
  832.   /* move past period, get the substring from the first character after the '.' to the last character (length) */
  833.   tailindex = tailindex + 1;
  834.   var type = image.substring(tailindex,image.length);
  835.  
  836.   /* convert extension to lower case */
  837.   if (type)
  838.     type = type.toLowerCase();
  839.  
  840.   // TODO: Will we convert .BMPs to a web format?
  841.   switch( type )
  842.   {
  843.     case "gif":
  844.     case "jpg":
  845.     case "jpeg":
  846.     case "png":
  847.       return true;
  848.       break;
  849.   }
  850.   return false;
  851. }
  852.  
  853. function InitMoreFewer()
  854. {
  855.   // Set SeeMore bool to the OPPOSITE of the current state,
  856.   //   which is automatically saved by using the 'persist="more"'
  857.   //   attribute on the dialog.MoreFewerButton button
  858.   //   onMoreFewer will toggle it and redraw the dialog
  859.   SeeMore = (dialog.MoreFewerButton.getAttribute("more") != "1");
  860.   onMoreFewer();
  861. }
  862.  
  863. function onMoreFewer()
  864. {
  865.   if (SeeMore)
  866.   {
  867.     dialog.MoreSection.setAttribute("collapsed","true");
  868.     window.sizeToContent();
  869.     dialog.MoreFewerButton.setAttribute("more","0");
  870.     dialog.MoreFewerButton.setAttribute("label",GetString("MoreProperties"));
  871.     SeeMore = false;
  872.   }
  873.   else
  874.   {
  875.     dialog.MoreSection.removeAttribute("collapsed");
  876.     window.sizeToContent();
  877.     dialog.MoreFewerButton.setAttribute("more","1");
  878.     dialog.MoreFewerButton.setAttribute("label",GetString("FewerProperties"));
  879.     SeeMore = true;
  880.   }
  881. }
  882.  
  883. function SwitchToValidatePanel()
  884. {
  885.   // no default implementation
  886.   // Only EdTableProps.js currently implements this
  887. }
  888.  
  889. function GetPrefs()
  890. {
  891.   var prefs;
  892.   try {
  893.     prefs = Components.classes['@mozilla.org/preferences;1'];
  894.     if (prefs) prefs = prefs.getService();
  895.     if (prefs) prefs = prefs.QueryInterface(Components.interfaces.nsIPref);
  896.     if (prefs)
  897.       return prefs;
  898.     else
  899.       dump("failed to get prefs service!\n");
  900.  
  901.   }
  902.   catch(ex)
  903.   {
  904.     dump("failed to get prefs service!\n");
  905.   }
  906.   return null;
  907. }
  908.  
  909. const nsIFilePicker = Components.interfaces.nsIFilePicker;
  910.  
  911. function GetLocalFileURL(filterType)
  912. {
  913.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  914.  
  915.   if (filterType == "img")
  916.   {
  917.     fp.init(window, GetString("SelectImageFile"), nsIFilePicker.modeOpen);
  918.     fp.appendFilters(nsIFilePicker.filterImages);
  919.   }
  920.   else if (filterType == "html")
  921.   {
  922.     fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
  923.  
  924.     // When loading into Composer, direct user to prefer HTML files and text files,
  925.     //   so we call separately to control the order of the filter list
  926.     fp.appendFilters(nsIFilePicker.filterHTML);
  927.     fp.appendFilters(nsIFilePicker.filterText);
  928.   }
  929.   // Default or last filter is "All Files"
  930.   fp.appendFilters(nsIFilePicker.filterAll);
  931.  
  932.   /* doesn't handle *.shtml files */
  933.   try {
  934.     var ret = fp.show();
  935.     if (ret == nsIFilePicker.returnCancel)
  936.       return null;
  937.   }
  938.   catch (ex) {
  939.     dump("filePicker.chooseInputFile threw an exception\n");
  940.     return null;
  941.   }
  942.  
  943.   return fp.fileURL.spec;
  944. }
  945.  
  946. function GetMetaElement(name)
  947. {
  948.   if (name)
  949.   {
  950.     name = name.toLowerCase();
  951.     if (name != "")
  952.     {
  953.       var metaNodes = editorShell.editorDocument.getElementsByTagName("meta");
  954.       if (metaNodes && metaNodes.length > 0)
  955.       {
  956.         for (var i = 0; i < metaNodes.length; i++)
  957.         {
  958.           var metaNode = metaNodes.item(i);
  959.           if (metaNode && metaNode.getAttribute("name") == name)
  960.             return metaNode;
  961.         }
  962.       }
  963.     }
  964.   }
  965.   return null;
  966. }
  967.  
  968. function CreateMetaElement(name)
  969. {
  970.   metaElement = editorShell.CreateElementWithDefaults("meta");
  971.   if (metaElement)
  972.     metaElement.setAttribute("name", name);
  973.   else
  974.     dump("Failed to create metaElement!\n");
  975.  
  976.   return metaElement;
  977. }
  978.  
  979. function GetHTTPEquivMetaElement(name)
  980. {
  981.   if (name)
  982.   {
  983.     name = name.toLowerCase();
  984.     if (name != "")
  985.     {
  986.       var metaNodes = editorShell.editorDocument.getElementsByTagName("meta");
  987.       if (metaNodes && metaNodes.length > 0)
  988.       {
  989.         for (var i = 0; i < metaNodes.length; i++)
  990.         {
  991.           var metaNode = metaNodes.item(i);
  992.           if (metaNode && metaNode.getAttribute("http-equiv").toLowerCase() == name)
  993.             return metaNode;
  994.         }
  995.       }
  996.     }
  997.   }
  998.   return null;
  999. }
  1000.  
  1001. function CreateHTTPEquivMetaElement(name)
  1002. {
  1003.   metaElement = editorShell.CreateElementWithDefaults("meta");
  1004.   if (metaElement)
  1005.     metaElement.setAttribute("http-equiv", name);
  1006.   else
  1007.     dump("Failed to create httpequivMetaElement!\n");
  1008.  
  1009.   return metaElement;
  1010. }
  1011.  
  1012. function CreateHTTPEquivElement(name)
  1013. {
  1014.   metaElement = editorShell.CreateElementWithDefaults("meta");
  1015.   if (metaElement)
  1016.     metaElement.setAttribute("http-equiv", name);
  1017.   else
  1018.     dump("Failed to create metaElement for http-equiv!\n");
  1019.  
  1020.   return metaElement;
  1021. }
  1022.  
  1023. // Change "content" attribute on a META element,
  1024. //   or delete entire element it if content is empty
  1025. // This uses undoable editor transactions
  1026. function SetMetaElementContent(metaElement, content, insertNew)
  1027. {
  1028.   if (metaElement)
  1029.   {
  1030.     if(!content || content == "")
  1031.     {
  1032.       if (!insertNew)
  1033.         editorShell.DeleteElement(metaElement);
  1034.     }
  1035.     else
  1036.     {
  1037.       if (insertNew)
  1038.       {
  1039.         metaElement.setAttribute("content", content);
  1040.         AppendHeadElement(metaElement);
  1041.       }
  1042.       else
  1043.         editorShell.SetAttribute(metaElement, "content", content);
  1044.     }
  1045.   }
  1046. }
  1047.  
  1048. function GetHeadElement()
  1049. {
  1050.   var headList = editorShell.editorDocument.getElementsByTagName("head");
  1051.   if (headList)
  1052.     return headList.item(0);
  1053.  
  1054.   return null;
  1055. }
  1056.  
  1057. function AppendHeadElement(element)
  1058. {
  1059.   var head = GetHeadElement();
  1060.   if (head)
  1061.   {
  1062.     var position = 0;
  1063.     if (head.hasChildNodes())
  1064.       position = head.childNodes.length;
  1065.  
  1066.     // Use editor's undoable transaction
  1067.     // Last param "true" says "don't change the selection"
  1068.     editorShell.InsertElement(element, head, position, true);
  1069.   }
  1070. }
  1071.  
  1072. function SetWindowLocation()
  1073. {
  1074.   gLocation = document.getElementById("location");
  1075.   if (gLocation)
  1076.   {
  1077.     window.screenX = Math.max(0, Math.min(window.opener.screenX + Number(gLocation.getAttribute("offsetX")),
  1078.                                           screen.availWidth - window.outerWidth));
  1079.     window.screenY = Math.max(0, Math.min(window.opener.screenY + Number(gLocation.getAttribute("offsetY")),
  1080.                                           screen.availHeight - window.outerHeight));
  1081.   }
  1082. }
  1083.  
  1084. function SaveWindowLocation()
  1085. {
  1086.   if (gLocation)
  1087.   {
  1088.     var newOffsetX = window.screenX - window.opener.screenX;
  1089.     var newOffsetY = window.screenY - window.opener.screenY;
  1090.     gLocation.setAttribute("offsetX", window.screenX - window.opener.screenX);
  1091.     gLocation.setAttribute("offsetY", window.screenY - window.opener.screenY);
  1092.   }
  1093. }
  1094.  
  1095. function onCancel()
  1096. {
  1097.   SaveWindowLocation();
  1098.   window.close();
  1099. }
  1100.  
  1101. function GetDefaultBrowserColors()
  1102. {
  1103.   var prefs = GetPrefs();
  1104.   var colors = new Object();
  1105.   var useSysColors = false;
  1106.   colors.TextColor = 0;
  1107.   colors.BackgroundColor = 0;
  1108.   try { useSysColors = prefs.GetBoolPref("browser.display.use_system_colors"); } catch (e) {}
  1109.  
  1110.   if (!useSysColors)
  1111.   {
  1112.     try { colors.TextColor = prefs.CopyCharPref("browser.display.foreground_color"); } catch (e) {}
  1113.  
  1114.     try { colors.BackgroundColor = prefs.CopyCharPref("browser.display.background_color"); } catch (e) {}
  1115.   }
  1116.   // Use OS colors for text and background if explicitly asked or pref is not set
  1117.   if (!colors.TextColor)
  1118.     colors.TextColor = "windowtext";
  1119.  
  1120.   if (!colors.BackgroundColor)
  1121.     colors.BackgroundColor = "window";
  1122.  
  1123.   colors.LinkColor = prefs.CopyCharPref("browser.anchor_color");
  1124.   colors.VisitedLinkColor = prefs.CopyCharPref("browser.visited_color");
  1125.  
  1126.   return colors;
  1127. }
  1128.  
  1129. function TextIsURI(selectedText)
  1130. {
  1131.   if (selectedText)
  1132.   {
  1133.     var text = selectedText.toLowerCase();
  1134.     return text.match(/^http:\/\/|^https:\/\/|^file:\/\/|^ftp:\/\/|\
  1135.                       ^about:|^mailto:|^news:|^snews:|^telnet:|\
  1136.                       ^ldap:|^ldaps:|^gopher:|^finger:|^javascript:/);
  1137.   }
  1138.   return false;
  1139. }
  1140.